﻿using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using FileListView;
using FreeX;
using System.Collections;

namespace FileExplorer
{
    /// <summary>
    /// Control to facilitate navigating through a directory structure
    /// </summary>
    public partial class FileExplorer : UserControl
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public FileExplorer()
        {
            InitializeComponent();
            history = new NavigationHistory();

            // Fill the main tree // 
            foreach (String drv in DriveList)
            {
                TreeNode rootNode = new TreeNode(drv);
                mainTree.Nodes.Add(rootNode);

                Fill(rootNode);
                mainTree.Nodes[0].Expand();
            } 
 
        }

        private ArrayList DriveList = new ArrayList(); 


        #region members

        private NavigationHistory history;

        private string m_InitialDirectory;

        /// <summary>
        /// Sets initial directory to load into FileListView
        /// </summary>
        public string InitialDirectory
        {
            get
            {
                return InitialDirectory;
            }
            set
            {
                m_InitialDirectory = value;
                history.Add(m_InitialDirectory);
                SetListviewAddress(m_InitialDirectory);

            }
        }

        /// <summary>
        /// represents a list of all items currently selected in the FileListView
        /// </summary>
        public ListView.SelectedListViewItemCollection SelectedItems
        {
            get
            {
                return LstMain.SelectedItems;
            }
        }

        //ColumnHeader c;


        /// <summary>
        /// the path currently pointed to by the FileListView control. Excludes the filename
        /// </summary>
        public string CurrentPath { get; set; }

        #endregion

        #region Private Methods

        private void ShowDirectoriesInListView(string thePath)
        {
            ListViewItem it;
            DirectoryInfo dir = new DirectoryInfo(thePath);

            foreach (DirectoryInfo subDir in dir.GetDirectories())
            {

                it = new ListViewItem(subDir.Name, 0);
                FillDirectoryDetails(subDir, it);
            }

            dir = null;
        }

        private void ShowFilesInListView(string thePath)
        {

            ListViewItem it;
            DirectoryInfo dir = new DirectoryInfo(thePath);
            string itemToolTip;

            LstMain.BeginUpdate();

            /* go through and show the directories */
            Image ic = FolderList.Images[0];

            /* add icon froom shell into image lists */
            LargeImageList.Images.Add(ic);
            SmallImageList.Images.Add(ic);
            ic = null;

            try
            {
                // loop through all file in the selected directory // 
                foreach (FileInfo f in dir.GetFiles())
                {
                    FreeXFileInfo ffi = new FreeXFileInfo(Path.Combine(CurrentPath, f.Name));
                    // depending on the view, set the appropriate icon size and details // 
                    if (LstMain.View == View.LargeIcon)
                    {

                        // this bit extracts the associated icon from the shell // 
                        LargeImageList.Images.Add(ffi.AssociatedIconLarge);
                        it = new ListViewItem(ffi.Filename, LargeImageList.Images.Count - 1);

                        // Set the tooltip with info 
                        itemToolTip = "Type: " + ffi.FileType + "\rSize: " + ffi.GetFormattedFileSize(FreeX.FreeXFileInfo.FileSizeFormat.Auto);
                        it.ToolTipText = itemToolTip;

                        // add the item 
                        LstMain.Items.Add(it);
                    }
                    else if (LstMain.View == View.SmallIcon)
                    {
                        SmallImageList.Images.Add(ffi.AssociatedIconSmall);
                        it = new ListViewItem(ffi.Filename, SmallImageList.Images.Count - 1);
                        LstMain.Items.Add(it);
                        // Set the tooltip with info 
                        // Set the tooltip with info 
                        itemToolTip = "Type: " + ffi.FileType + "\rSize: " + ffi.GetFormattedFileSize(FreeX.FreeXFileInfo.FileSizeFormat.Auto);
                        it.ToolTipText = itemToolTip;
                    }
                    else
                    {
                        SmallImageList.Images.Add(ffi.AssociatedIconSmall);
                        //it = new ListViewItem(ffi.Filename, SmallImageList.Images.Count - 1);
                        // Use this to get all of the file info // 
                        FillFileDetails(ffi);
                    }

                    ffi = null;

                }
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Data.ToString(), "Error");
            }

            /* A couple of ListView setting */
            LstMain.AutoResizeColumns(ColumnHeaderAutoResizeStyle.HeaderSize);
            LstMain.EndUpdate();
        }

        private void FillDirectoryDetails(DirectoryInfo thePath, ListViewItem theItem)
        {

            ListViewItem.ListViewSubItem size = new ListViewItem.ListViewSubItem(theItem, "");
            ListViewItem.ListViewSubItem type = new ListViewItem.ListViewSubItem(theItem, "Directory");

            ListViewItem.ListViewSubItem createDate = new ListViewItem.ListViewSubItem(theItem, thePath.CreationTime.ToShortDateString());
            ListViewItem.ListViewSubItem modDate = new ListViewItem.ListViewSubItem(theItem, thePath.LastWriteTime.ToShortDateString());
            ListViewItem.ListViewSubItem accessedDate = new ListViewItem.ListViewSubItem(theItem, thePath.LastAccessTime.ToShortDateString());
            ListViewItem.ListViewSubItem description = new ListViewItem.ListViewSubItem(theItem, string.Empty);
            ListViewItem.ListViewSubItem attributes = new ListViewItem.ListViewSubItem(theItem, thePath.Attributes.ToString());


            theItem.SubItems.Add(size);
            theItem.SubItems.Add(type);
            theItem.SubItems.Add(createDate);
            theItem.SubItems.Add(modDate);
            theItem.SubItems.Add(accessedDate);
            theItem.SubItems.Add(description);
            theItem.SubItems.Add(attributes);

            LstMain.Items.Add(theItem);

        }

        private void FillFileDetails(FreeXFileInfo ffi)
        {
            ListViewItem theItem = new ListViewItem(ffi.Filename, SmallImageList.Images.Count - 1);
            ListViewItem.ListViewSubItem size = new ListViewItem.ListViewSubItem(theItem, ffi.GetFormattedFileSize(FreeXFileInfo.FileSizeFormat.Auto));
            ListViewItem.ListViewSubItem type = new ListViewItem.ListViewSubItem(theItem, ffi.FileType);

            ListViewItem.ListViewSubItem createDate = new ListViewItem.ListViewSubItem(theItem, ffi.DateCreated.ToShortDateString());
            ListViewItem.ListViewSubItem modDate = new ListViewItem.ListViewSubItem(theItem, ffi.DateModified.ToShortDateString());
            ListViewItem.ListViewSubItem accessedDate = new ListViewItem.ListViewSubItem(theItem, ffi.DateLastAccessed.ToShortDateString());
            ListViewItem.ListViewSubItem description = new ListViewItem.ListViewSubItem(theItem, ffi.Description);
            ListViewItem.ListViewSubItem attributes = new ListViewItem.ListViewSubItem(theItem, ffi.Attributes);

            ListViewItem.ListViewSubItem comments = new ListViewItem.ListViewSubItem(theItem, ffi.Comments);
            ListViewItem.ListViewSubItem copyRight = new ListViewItem.ListViewSubItem(theItem, ffi.Copyright);

            ListViewItem.ListViewSubItem dimensions;
            ListViewItem.ListViewSubItem height;
            ListViewItem.ListViewSubItem width;
            ListViewItem.ListViewSubItem vRes;
            ListViewItem.ListViewSubItem hRes;

            if (ffi.FileExtension.ToLower() == ".gif" || ffi.FileExtension.ToLower() == ".png" || ffi.FileExtension.ToLower() == ".bmp")
            {
                dimensions = new ListViewItem.ListViewSubItem(theItem, "");
                height = new ListViewItem.ListViewSubItem(theItem, ffi.Height.ToString());
                width = new ListViewItem.ListViewSubItem(theItem, ffi.Width.ToString());
                vRes = new ListViewItem.ListViewSubItem(theItem, ffi.VerticalResolution.ToString());
                hRes = new ListViewItem.ListViewSubItem(theItem, ffi.HorizontalResolution.ToString());
            }
            else
            {
                dimensions = new ListViewItem.ListViewSubItem(theItem, "");
                height = new ListViewItem.ListViewSubItem(theItem, "");
                width = new ListViewItem.ListViewSubItem(theItem, "");
                vRes = new ListViewItem.ListViewSubItem(theItem, "");
                hRes = new ListViewItem.ListViewSubItem(theItem, "");
            }

            theItem.SubItems.Add(size);
            theItem.SubItems.Add(type);
            theItem.SubItems.Add(createDate);
            theItem.SubItems.Add(modDate);
            theItem.SubItems.Add(accessedDate);
            theItem.SubItems.Add(description);
            theItem.SubItems.Add(attributes);

            theItem.SubItems.Add(comments);
            theItem.SubItems.Add(copyRight);
            theItem.SubItems.Add(dimensions);
            theItem.SubItems.Add(height);
            theItem.SubItems.Add(width);
            theItem.SubItems.Add(vRes);
            theItem.SubItems.Add(hRes);
            LstMain.Items.Add(theItem);
            // Set the tooltip with info 
            string itemToolTip = "Type: " + ffi.FileType + "\rSize:" + ffi.GetFormattedFileSize(FreeX.FreeXFileInfo.FileSizeFormat.Auto);
            theItem.ToolTipText = itemToolTip;

        }

        private void SetNavigationButtons()
        {
            if (history.CanGoBack())
            {
                TsBack.Enabled = true;
            }
            else
            {
                TsBack.Enabled = false;
            }

            if (history.CanGoForward())
            {
                TsForward.Enabled = true;
            }
            else
            {
                TsForward.Enabled = false;
            }

            if (history.CanGoUp())
            {
                TsUp.Enabled = true;
            }
            else
            {
                TsUp.Enabled = false;
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Handles loading the listview with the currently selected path
        /// </summary>
        /// <param name="path">the path to set the control to</param>
        public void SetListviewAddress(string path)
        {
            /* using getFullPath to clean the path string */
            CboAddress.Text = Path.GetFullPath(path);
            CurrentPath = CboAddress.Text;
            ShowDirectoriesInListView(path);
            ShowFilesInListView(path);

            SetNavigationButtons();
        }

        /// <summary>
        /// Reloads the current path into the FileView
        /// </summary>
        public void RefreshView()
        {
            ShowFilesInListView(CurrentPath);
        }

        /// <summary>
        /// NOT YET IMPLEMENTED
        /// </summary>
        /// <param name="index">index of column to manipulate</param>
        /// <param name="visible">true to show column, false to hide it</param>
        public void SetColumnVisible(int index, bool visible)
        {
            if (visible)
            {
                LstMain.Columns.Insert(index, LstMain.Columns[index].Text);
            }
            else
            {
                LstMain.Columns.RemoveAt(index);
            }
        }

        #endregion

        #region Listview Events

        private void CboAddress_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Return)
            {
                CurrentPath = CboAddress.Text;
                // Figure out if its a directory or a file // 
                //SetSelectedItemInformation(CurrentPath);
                FileInfo fi = new FileInfo(CurrentPath);
                if ((fi.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
                {
                    // Its a directory // 
                    LstMain.Items.Clear();
                    ShowDirectoriesInListView(CurrentPath);
                    ShowFilesInListView(CurrentPath);
                    /* add directory to the path history */
                    history.Add(CurrentPath);
                }
                else
                {
                    System.Diagnostics.Process.Start(CurrentPath);

                }
            }
        }

        private void TsBack_Click(object sender, EventArgs e)
        {
            if (history.CanGoBack())
            {
                SetListviewAddress(history.GoBack());
            }
        }

        private void TsForward_Click(object sender, EventArgs e)
        {
            if (history.CanGoForward())
            {
                SetListviewAddress(history.GoForward());
            }
        }

        private void TsUp_Click(object sender, EventArgs e)
        {
            if (history.CanGoUp())
            {
                string up = history.GoUp();
                history.Add(up);
                SetListviewAddress(up);
            }
        }

        private void LstMain_ItemActivate(object sender, EventArgs e)
        {
            // Figure out if its a directory or a file // 
            //SetSelectedItemInformation(CurrentPath);
            string selectedItemPath = Path.Combine(CboAddress.Text, SelectedItems[0].Text);
            FileInfo fi = new FileInfo(selectedItemPath);
            if ((fi.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
            {
                // Its a directory // 
                LstMain.Items.Clear();
                ShowDirectoriesInListView(selectedItemPath);
                ShowFilesInListView(selectedItemPath);
                CboAddress.Text = selectedItemPath;
                CurrentPath = selectedItemPath;
                /* add directory to the path history */
                history.Add(CurrentPath);
                SetNavigationButtons();
            }
            else
            {
                System.Diagnostics.Process.Start(selectedItemPath);

            }
        }

        private void LstMain_SelectedIndexChanged(object sender, EventArgs e)
        {
            /* check to see if something is selected, then set ability to cut and copy */
            //if (LstMain.SelectedItems.Count > 0)
            //{
            //    ctxCopy.Visible = true;
            //    ctxCut.Visible = true;
            //    ctxDelete.Visible = true;
            //}
            //else
            //{
            //    ctxCopy.Visible = false;
            //    ctxCut.Visible = false;
            //    ctxDelete.Visible = false;
            //}
        }

        private void LstMain_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            // Create and/or configure the ListViewItemComparer to sort based on 
            // the column that was clicked.  
            ListViewSort sorter = LstMain.ListViewItemSorter as ListViewSort;

            if (sorter == null)
            {
                // Create a new ListViewItemComparer. 
                sorter = new ListViewSort(e.Column);
                LstMain.ListViewItemSorter = sorter;
            }
            else
            {
                // Configure the existing ListViewItemComparer. 
                sorter.Column = e.Column;
            }

            // Sort the ListView 
            LstMain.Sort();
        }

        private void LstMain_DragDrop(object sender, DragEventArgs e)
        {
            string[] files = e.Data.GetData(DataFormats.FileDrop) as string[];
            DragDropEffects dde;
            if ((e.KeyState & 4) == 4)
            {
                dde = DragDropEffects.Move;
            }
            else
            {
                dde = DragDropEffects.Copy;
            }

            for (int i = 0; i < files.Length; i++)
            {
                FreeXClipboard.Drop(CurrentPath, files[i], dde);
            }
            RefreshView();
        }

        private void LstMain_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effect = DragDropEffects.Copy;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        private void LstMain_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {

                string[] files = new string[LstMain.SelectedItems.Count];
                int ctr = 0;
                string fullPath;

                foreach (ListViewItem item in LstMain.SelectedItems)
                {
                    fullPath = Path.Combine(CurrentPath, item.Text);
                    files[ctr] = fullPath;
                    ctr++;
                }

                IDataObject data = new DataObject(DataFormats.FileDrop, files);
                LstMain.DoDragDrop(data, DragDropEffects.Copy);
            }
        }

        #endregion



        /// <summary> 
        /// Recursive tree fill 
        /// </summary> 
        /// <param name="dirNode"></param> 
        ///  
        private void Fill(TreeNode dirNode)
        {
            DirectoryInfo dir = new DirectoryInfo(dirNode.FullPath);

            foreach (DirectoryInfo dirItem in dir.GetDirectories())
            {
                TreeNode nde = new TreeNode(dirItem.Name);
                dirNode.Nodes.Add(nde);
                nde.Nodes.Add("*");
            }
        }

        private void EnumerateDrives()
        {

            DriveInfo[] s = DriveInfo.GetDrives();
            foreach (DriveInfo d in s)
            {
                // only list drives that are available // 
                if (d.IsReady == true)
                {
                    // add them to the drive menu bar // 
                    ToolStripButton i = new ToolStripButton();
                    i.Text = d.Name.Replace("\\", string.Empty);
                    // tag contains root path // 
                    i.Tag = i.Text + @"\";
                    i.ToolTipText = d.VolumeLabel;
                    // the current drive image is weird // 
                    i.ImageAlign = ContentAlignment.TopCenter;
                    i.TextAlign = ContentAlignment.BottomCenter;

                    // set the icon according to drive type // 
                    if (d.DriveType == DriveType.Network)
                    {
                        i.Image = FolderList.Images[5];
                    }
                    else if (d.DriveType == DriveType.CDRom)
                    {
                        i.Image = FolderList.Images[2];
                    }
                    else
                    {
                        i.Image = FolderList.Images[12];
                    }

                    DriveList.Add(d.Name);
                }
            }

        }

        private void mainTree_BeforeExpand(object sender, TreeViewCancelEventArgs e)
        {
            if (e.Node.Nodes[0].Text == "*")
            {
                e.Node.Nodes.Clear();
                Fill(e.Node);
            } 
 
        }

        private void mainTree_AfterSelect(object sender, TreeViewEventArgs e)
        {
            // Set the path for the selected node // 
           // SetSelectedItemInformation(Path.GetFullPath(e.Node.FullPath));
            // clear the image lists and listview // 
            LargeImageList.Images.Clear();
            SmallImageList.Images.Clear();
            LstMain.Items.Clear();
            // get the files and show them // 
            ShowFilesInListView(CurrentPath);
            // set the path in the address combo box // 
            CboAddress.Text = CurrentPath; 
 
        } 
 

 
    }
}
